#ifndef __CPU_H__
#define __CPU_H__
#include <cdefs.h>
#include <stdint.h>
#include <stdbool.h>
#include <util.h>
#include <arch/cpu.h>
#include <spinlock.h>
#include <list.h>
#include <plat.h>


#ifndef __ASSEMBLER__
extern uint8_t _cpu_if_base;

typedef struct {
    list_t event_list;

} cpuif_t;

typedef struct {
    uint64_t handler;
    uintptr_t event;
    uintptr_t data;
} cpu_msg_t;

typedef struct {
    spinlock_t lock;
    volatile uint64_t n;
    volatile bool ready;
    volatile uint64_t count;
} cpu_synctoken_t;

extern cpu_synctoken_t cpu_glb_sync;

static inline bool cpu_is_master(void)
{
    return get_cpuid() == 0;
}

static inline void cpu_sync_init(cpu_synctoken_t* token, uint64_t n)
{
    token->lock = SPINLOCK_INITVAL;
    token->n = n;
    token->count = 0;
    token->ready = true;
}

static inline void cpu_sync_barrier(cpu_synctoken_t* token)
{
    // TODO: no fence/barrier needed in this function?

    uint64_t next_count = 0;

    while (!token->ready);

    spin_lock(&token->lock);
    token->count++;
    next_count = ALIGN(token->count, token->n);
    spin_unlock(&token->lock);

    while (token->count < next_count);
}


void cpu_init(void);
void cpu_idle(void);
void cpu_msg_handler(unsigned int irq);
void cpu_send_msg(uint64_t trgtcpu, cpu_msg_t *msg);

typedef void (*cpu_msg_handler_t)(uintptr_t event, uintptr_t data);

#define DECLARE_CPU_MSG_HANDLER(handler, handler_id)                \
    __section(".ipi_cpumsg_handlers") __used                        \
        cpu_msg_handler_t __cpumsg_handler_##handler = handler;     \
    __section(".ipi_cpumsg_handlers_id") __used                     \
        volatile const uint64_t handler_id;

#endif /* __ASSEMBLER__ */

#endif /* #define __CPU_H__ */
